import asyncio
import os
from openai import OpenAI
from dotenv import load_dotenv
from contextlib import AsyncExitStack

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import json  # 添加 json 模块导入

# 加载.env文件
load_dotenv()


class MCPCLient:
    def __init__(self):
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        self.openai_api_key = os.getenv("OPENAI_API_KEY")
        self.base_url = os.getenv("BASE_URL")
        self.model = os.getenv("MODEL")

        if not self.openai_api_key:
            raise ValueError("OPENAI_API_KEY 未设置")
        
        self.client = OpenAI(
            api_key=self.openai_api_key, 
            base_url=self.base_url
            )

    async def process_query(self, query: str) -> str:
        """使用大模型处理查询并调用可用的MCP工具（Function Call版本）"""
        messages = [
            # {"role": "system", "content": "你是一个helpful智能助手，帮助用户回答问题。"},
            {"role": "user", "content": query}
        ]
        print(messages)
        response = await self.session.list_tools()

        # 将mcp提供的tools list转化为tools的格式
        available_tools = [{ 
            "type": "function",
            "function": {
                "name": tool.name,
                "description": tool.description,
                "parameters": tool.inputSchema
            }
        } for tool in response.tools]
        # print("可用工具：", available_tools)
        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            tools=available_tools,
        )

        final_text = []

        # 处理返回的内容
        context = response.choices[0]
        if context.finish_reason == "tool_calls":
            # Bug修复：修正变量名
            tool_call = context.message.tool_calls[0]
            tool_name = tool_call.function.name
            tool_args = json.loads(tool_call.function.arguments)

            # 执行工具
            result = await self.session.call_tool(tool_name, tool_args)
            print(f"\n\n[Calling tool {tool_name} with args {tool_args}]\n\n")

            # 添加对话记录
            # Bug修复：修正变量名
            messages.append(context.message.model_dump())
            messages.append({
                "role": "tool",
                "content": result.content[0].text,
                "tool_call_id": tool_call.id
            })

            # 再次调用大模型
            response = self.client.chat.completions.create(
                model=self.model,
                messages=messages,
            )
            return response.choices[0].message.content

        return context.message.content
    async def connect_to_mock_server(self):
        print("MCP客户端已初始化，但未连接到服务器。")

    async def connect_to_server(self, server_script_path: str):
        """连接到MCP服务器并列出可用工具"""
        is_python = server_script_path.endswith(".py")
        is_js = server_script_path.endswith(".js")
        
        if not is_python and not is_js:
            raise ValueError("MCP Server 脚本必须是Python或JavaScript文件。")

        command = "python" if is_python else "node"

        server_params = StdioServerParameters(
            command=command,
            args=[server_script_path],
            env=None
        )

        # 更新session
        stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
        self.stdio, self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))

        await self.session.initialize()

        # 列出可用工具
        response = await self.session.list_tools()
        tools = response.tools
        print("已连接到MCP服务器，可用工具：", [tool.name for tool in tools])

    async def chat_loop(self):
        print("客户端已启去吧！输入`quit`退出.")

        while True:
            try:
                query = input("\n请输入命令: ").strip()
                if query.lower() =='quit':
                    break

                response = await self.process_query(query)

                print(f"\n [AI]: {response}")
            except Exception as e:
                print(f"[ERROR]: {str(e)}")
    
    async def cleanup(self):
        await self.exit_stack.aclose()

async def main():
    # 初始化客户端并启动聊天循环
    # 在这里添加你的客户端初始化逻辑
    # 例如，连接到服务器、设置事件处理程序等

    # 修改部分：当没有传入参数时，默认使用 server.py
    server_script_path = sys.argv[1] if len(sys.argv) > 1 else 'server.py'

    client = MCPCLient()
    try:
        await client.connect_to_server(server_script_path)
        await client.chat_loop()
    finally:
        await client.cleanup()

if __name__ == "__main__":
    import sys
    asyncio.run(main())